package com.hcss.common.tx;

import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.interceptor.*;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * @desc 事务配置类
 * @author maxiaoming
 * @date 2018年6月19日 下午4:19:07
 * @company 浙江鸿程计算机系统有限公司 
 */
@Aspect
@Configuration
public class TransactionConfig {

	/**
	 * 注解切面匹配表达式
	 * com.hcss包或者子包下的，service包下的以Service结尾的所有类的所有方法
	 */
	private static final String TX_ADVICE_POINTCUT_EXPRESSION = "execution(public * com.hcss..*.service.*Service.*(..))";
	
	@Autowired
	private DataSourceTransactionManager txManager;
	
	@Bean
	public TransactionInterceptor getTxInterceptor(){
		NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();

        // 只读，不支持事务
        RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
        readOnlyTx.setReadOnly(true);
        readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);

        // 支持事务，事务传播类型是REQUIRED，事务隔离机制是READ_COMMITTED
        RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
        requiredTx.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        requiredTx.setIsolationLevel(Isolation.READ_COMMITTED.value());

        Map<String, TransactionAttribute> txMap = new HashMap<>(16);

        // 以下开头的方法，需要支持事务
        txMap.put("add*", requiredTx);
        txMap.put("save*", requiredTx);
        txMap.put("insert*", requiredTx);
        txMap.put("create*", requiredTx);
        txMap.put("batch*", requiredTx);
        txMap.put("update*", requiredTx);
        txMap.put("modify*", requiredTx);
        txMap.put("delete*", requiredTx);
        // 以下开头的方法，不需要支持事务
        txMap.put("get*", readOnlyTx);
        txMap.put("query*", readOnlyTx);
        txMap.put("find*", readOnlyTx);
        txMap.put("select*", readOnlyTx);
        // 默认支持事务
        txMap.put("*", requiredTx);
        source.setNameMap(txMap);

        return new TransactionInterceptor(txManager, source);
	}
	
	/**
	 * 配置事务切面
	 */
	@Bean
    public Advisor txAdviceAdvisor() {
		TransactionInterceptor txAdvice = getTxInterceptor();
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(TX_ADVICE_POINTCUT_EXPRESSION);
        return new DefaultPointcutAdvisor(pointcut, txAdvice);
    }
}
